#pragma once
#include "ec_search.hpp"
#include "user.hxx"
#include "message.hxx"
#include <memory>

class ESClientFactory {
public:
    static std::shared_ptr<elasticlient::Client> create(const std::vector<std::string>& es_addr_list) {
        return std::make_shared<elasticlient::Client>(es_addr_list);
    }
};

class ESUser {
public:
    using ptr = std::shared_ptr<ESUser>;
    ESUser(const std::shared_ptr<elasticlient::Client>& es_client)
        : _es_client(es_client) {}
    bool createIndex() {
        ESIndex index(_es_client, "user");
        index.append("user_id" ,"keyword", "standard");
        index.append("user_id" ,"keyword", "standard");
        index.append("user_id" ,"keyword", "standard");
        index.append("user_name");
        index.append("description", "text", "standard", false);
        index.append("phone", "keyword", "standard");
        index.append("avatar_id", "keyword", "standard", false);
        bool ret = index.create();
        if(!ret) {
            LOG_ERROR("创建索引 user 失败");
            return false;
        }
        LOG_INFO("创建索引 user 成功");
        return true;
    }


    bool appendData(const std::string& user_id,
                    const std::string& user_name,
                    const std::string& phone,
                    const std::string& description = "",
                    const std::string& avatar_id = "") {
        bool ret = ESInsert(_es_client, "user")
        .append("user_id", user_id)
        .append("user_name", user_name)
        .append("phone", phone)
        .append("description", description)
        .append("avatar_id", avatar_id)
        .insert(user_id);
        if(!ret) {
            LOG_ERROR("新增/更新用户数据 {} 失败", user_id);
            return false;
        }
        LOG_INFO("新增/更新用户数据 {} 成功", user_id);
        return ret;
    }


    //key可以为任意可搜索的字段值, user_id_list是需要排除的user_id
    std::vector<User> search(const std::string& key, const std::vector<std::string>& user_id_list) {
        Json::Value hits = ESSearch(_es_client, "user")
        .append_should_match("user_name", key)
        .append_should_match("phone.keyword", key)
        .append_should_match("user_id.keyword", key)
        .append_must_not_terms("user_id.keyword", user_id_list)
        .search();
        if(hits.isArray() == false) {
            LOG_ERROR("查询用户数据失败, hits不是数组: {}", hits.toStyledString());
            return {};
        }
        // std::string tmp;
        // Serialize(hits, tmp);
        // LOG_DEBUG("查询用户数据: [{}]", tmp);
        std::vector<User> user_list;
        LOG_INFO("查询到{}条用户数据", hits.size());
        for(const auto& hit : hits) {
            User user;
            user.set_user_id(hit["_source"]["user_id"].asString());
            user.set_user_name(hit["_source"]["user_name"].asString());
            user.set_phone(hit["_source"]["phone"].asString());
            user.set_description(hit["_source"]["description"].asString());
            user.set_avatar_id(hit["_source"]["avatar_id"].asString());
            user_list.emplace_back(user);
        }
        return user_list;
    }
private:
    std::shared_ptr<elasticlient::Client> _es_client;
};


class ESMessage {
public:
    using ptr = std::shared_ptr<ESMessage>;
    ESMessage(const std::shared_ptr<elasticlient::Client>& es_client)
        : _es_client(es_client) {}


    bool createIndex() {
        bool ret = ESIndex(_es_client, "message")
        .append("message_id", "keyword", "standard", false)
        .append("session_id", "keyword")
        .append("user_id", "keyword", "standard", false)
        .append("create_time", "long", "standard", false)
        .append("content", "text")
        .create();
        if(!ret) {
            LOG_ERROR("创建索引 message 失败");
            return false;
        }
        LOG_INFO("创建索引 message 成功");  
        return true;
    }


    bool appendData(const std::string& message_id,
                    const std::string& session_id,
                    const std::string& user_id,
                    const long create_time,
                    const std::string& content = "") {
        bool ret = ESInsert(_es_client, "message")
        .append("message_id", message_id)
        .append("session_id", session_id)
        .append("user_id", user_id)
        .append("create_time", create_time)
        .append("content", content)
        .insert(message_id);
        if(!ret) {
            LOG_ERROR("新增/更新消息数据 {} 失败", message_id);
            return false;
        }
        LOG_INFO("新增/更新消息数据 {} 成功", message_id);
        return ret;
    }

    // 移除所有id为 message_id 的记录
    bool remove(const std::string& message_id) {
        bool ret = ESRemove(_es_client, "message")
        .remove(message_id);
        if(!ret) {
            LOG_ERROR("删除消息数据 {} 失败", message_id);
            return false;
        }
        LOG_INFO("删除消息数据 {} 成功", message_id);
        return ret;
    }


    // 在指定会话中根据文本关键词搜索消息
    std::vector<Message> search(const std::string& session_id, const std::string& key) {
        Json::Value hits = ESSearch(_es_client, "message")
        .append_must_term("session_id.keyword", session_id)
        .append_must_match("content", key)
        .search();
        if(hits.isArray() == false) {
            LOG_ERROR("查询消息数据失败, hits不是数组: {}", hits.toStyledString());
            return {};
        }
        std::vector<Message> message_list;
        LOG_INFO("查询到{}条消息数据", hits.size());
        for(const auto& hit : hits) {
            Message message;
            message.set_message_id(hit["_source"]["message_id"].asString());
            message.set_session_id(hit["_source"]["session_id"].asString());
            message.set_user_id(hit["_source"]["user_id"].asString());
            boost::posix_time::ptime create_time = boost::posix_time::from_time_t(hit["_source"]["create_time"].asInt64());
            message.set_create_time(create_time);
            message.set_content(hit["_source"]["content"].asString());
            message_list.emplace_back(message);
        }
        return message_list;
    }
private:
    std::shared_ptr<elasticlient::Client> _es_client;
};